﻿using AiQiuQuan.Sport.Core;
using AiQiuQuan.Sport.Core.Tool;
using AiQiuQuan.Sport.Model;
using AiQiuQuan.Sport.Model.Enums;
using AiQiuQuan.Sport.Model.Models;
using AiQiuQuan.Sport.WebApi.Entities;
using AiQiuQuan.Sport.WebApi.Repositories;
using AiQiuQuan.Sport.WebClient;
using DotNetCore.CAP;
using Microsoft.EntityFrameworkCore;
using RedLockNet;

namespace AiQiuQuan.Sport.WebApi.SubscribeServices.Impl
{
    /// <summary>
    /// 支付回调
    /// </summary>
    public class PayCallbackService : ICapSubscribe, IPayCallbackService
    {
        private readonly ApiUrl _apiUrl;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IPayOrderRepository _payOrderRepository;
        private readonly ISiteOrderRepository _siteOrderRepository;
        private readonly ILogger<PayCallbackService> _logger;
        private readonly IWeChatPayOrderDetailedRepository _weChatPayOrderRepository;
        private readonly IVenueClientService _venueClientService;
        private readonly IRefundOrderRepository _refundOrderRepository;
        private readonly IVenueInfoAccountRepository _venueInfoAccountRepository;
        private readonly IVenueInfoAccountDetailRepository _venueInfoAccountDetailRepository;
        private readonly IGameOrderRepository _gameOrderRepository;
        private readonly IActivityUserRepository _activityUserRepository;
        private readonly IDistributedLockFactory _distributedLockFactory;
        private readonly IActivityRepository _activityRepository;

        /// <summary>
        /// ctor
        /// </summary>
        public PayCallbackService(
            IPayOrderRepository payOrderRepository,
            IWeChatPayOrderDetailedRepository weChatPayOrderRepository,
            ISiteOrderRepository siteOrderRepository,
            ILogger<PayCallbackService> logger,
            IVenueClientService venueClientService,
            ApiUrl apiUrl,
            IUnitOfWorkManager unitOfWorkManager,
            IRefundOrderRepository refundOrderRepository,
            IVenueInfoAccountRepository venueInfoAccountRepository,
            IVenueInfoAccountDetailRepository venueInfoAccountDetailRepository,
            IGameOrderRepository gameOrderRepository,
            IActivityUserRepository activityUserRepository,
            IDistributedLockFactory distributedLockFactory,
            IActivityRepository activityRepository)
        {
            _apiUrl = apiUrl;
            _logger = logger;
            _payOrderRepository = payOrderRepository;
            _weChatPayOrderRepository = weChatPayOrderRepository;
            _siteOrderRepository = siteOrderRepository;
            _venueClientService = venueClientService;
            _unitOfWorkManager = unitOfWorkManager;
            _refundOrderRepository = refundOrderRepository;
            _venueInfoAccountRepository = venueInfoAccountRepository;
            _venueInfoAccountDetailRepository = venueInfoAccountDetailRepository;
            _gameOrderRepository = gameOrderRepository;
            _activityUserRepository = activityUserRepository;
            _distributedLockFactory = distributedLockFactory;
            _activityRepository = activityRepository;
        }


        /// <summary>
        /// 微信支付回调
        /// </summary>
        [CapSubscribe(MessageTopic.ALL_PAY_CALLBACK, Group = MessageTopic.ALL_PAY_CALLBACK)]
        public async Task PayAsync(PayCallbackContent content)
        {
            var payOrder = await _payOrderRepository.FirstOrDefaultAsync(m => m.OrderNo == content.OrderNo);
            if (payOrder == null || payOrder.PayState != PayOrderStateEnum.NotPay)
            {
                _logger.LogError($"未查询到支付单或订单已处理：{(payOrder == null ? "" : payOrder.PayState.ToEnumDescription())}");
                return;
            }

            payOrder.PayId = content.PayId;
            payOrder.PayTime = content.CompleteTime;
            payOrder.PayState = content.TradeState == "SUCCESS"
                ? PayOrderStateEnum.Paid
                : content.TradeState == "PAYERROR"
                    ? PayOrderStateEnum.PayFaild
                    : PayOrderStateEnum.Canceled;

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _payOrderRepository.UpdateAsync(payOrder);
                if (payOrder.PayState == PayOrderStateEnum.Paid)
                {
                    await ExecutePaySuccessAsync(content);
                }
                else
                {
                    _logger.LogError($"支付失败：{content.TradeState}");
                }

                await uow.CompleteAsync();
            }
        }

        /// <summary>
        /// 微信退款回调
        /// </summary>
        [CapSubscribe(MessageTopic.ALL_REFUND_CALLBACK, Group = MessageTopic.ALL_REFUND_CALLBACK)]
        public async Task RefundAsync(RefundResultDto content)
        {
            var refund = await _refundOrderRepository.FirstOrDefaultAsync(m => m.RefundNo == content.RefundNo);
            if (refund == null || refund.State != RefundStateEnum.Processing)
            {
                _logger.LogError($"未查询到退款单或退款单已处理：{(refund == null ? "" : refund.State.ToEnumDescription())}");
                return;
            }

            refund.RefundId = content.RefundId ?? string.Empty;
            refund.State = content.IsSuccess ? RefundStateEnum.Sucess : RefundStateEnum.Faild;
            refund.Remark = content.Msg ?? string.Empty;
            refund.RefundTime = DateTimeOffset.Now;

            var payOrder = await _payOrderRepository.FirstOrDefaultAsync(m => m.ID == refund.PayOrderId);
            payOrder.RefundAmount += refund.RefundAmount;
            payOrder.PayState = payOrder.RefundAmount == payOrder.PayAmount ? PayOrderStateEnum.Refunded : PayOrderStateEnum.PartialRefunded;
            payOrder.RefundTime = DateTimeOffset.Now;

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _refundOrderRepository.UpdateAsync(refund);
                if (refund.State != RefundStateEnum.Faild)
                {
                    await _payOrderRepository.UpdateAsync(payOrder);
                    await ExecuteRefundSuccessAsync(refund, payOrder);
                }
                else
                {
                    _logger.LogError($"退款失败：{content.Msg}");
                }

                await uow.CompleteAsync();
            }
        }

        #region private methods

        /// <summary>
        /// 支付成功，分业务类型处理相关逻辑
        /// </summary>
        private async Task ExecutePaySuccessAsync(PayCallbackContent content)
        {
            var attach = content.Attach;
            switch (attach.BusinessType)
            {
                case BusinessTypeEnum.VenueSite:
                    await SetVenueOrderAsync(content);
                    break;
                case BusinessTypeEnum.Activity:
                    await SetActivityOrderAsync(content);
                    break;
            }
        }
        #region 支付成功 相关业务逻辑
        /// <summary>
        /// 场馆订单支付成功逻辑
        /// </summary>
        private async Task SetVenueOrderAsync(PayCallbackContent model)
        {
            //兼容原场馆订单支付逻辑
            var weChatPayOrderModel = await _weChatPayOrderRepository.FirstOrDefaultAsync(x => x.WPOD_OrderNo == model.OrderNo);
            if (weChatPayOrderModel != null)
            {
                weChatPayOrderModel.WPOD_WeChatOrderNo = model.PayId;
                weChatPayOrderModel.WPOD_ReturnParam = string.Empty;
                weChatPayOrderModel.WPOD_PayDateTime = model.CompleteTime;
                weChatPayOrderModel.WPOD_State = PayOrderStateEnum.Paid;
                await _weChatPayOrderRepository.UpdateAsync(weChatPayOrderModel);
            }

            var siteOrder = await _siteOrderRepository.FirstOrDefaultAsync(m => m.SO_OrderNo == model.OrderNo);
            if (siteOrder != null)
            {
                siteOrder.SO_WeChatOrderNo = model.PayId;
                siteOrder.SO_State = VenueOrderStateEnum.NoUse;
                await _siteOrderRepository.UpdateAsync(siteOrder);
            }

            //发送公众号通知消息
            if (siteOrder != null)
            {
                try
                {
                    await _venueClientService.VenueMemberCardPaySuccessAsync(_apiUrl.BaseUrl, siteOrder.ID);
                }
                catch (Exception ex)
                {
                    _logger.LogError($"支付成功，发送公众号消息失败：{ex.Message}");
                }
            }
        }

        /// <summary>
        /// 活动订单支付成功逻辑
        /// </summary>
        /// <returns></returns>
        private async Task SetActivityOrderAsync(PayCallbackContent model)
        {
            var gameOrder = await _gameOrderRepository.FirstOrDefaultAsync(m => m.OrderNo == model.OrderNo);
            if (gameOrder != null)
            {
                //更新活动订单状态
                gameOrder.State = GameOrderStateEnum.Paid;
                await _gameOrderRepository.UpdateAsync(gameOrder);
                //更新订单对应的用户报名状态
                var builder = await _activityUserRepository.UpdatePartialAsync();
                await builder.Set(m => m.PayState, PayOrderStateEnum.Paid).Set(m => m.JoinState, GameJoinStateEnum.JoinCompleted)
                    .Where(m => m.GameOrderId == gameOrder.ID).ExecuteAsync();

            }
        }
        #endregion

        /// <summary>
        /// 退款成功，分业务类型处理相关逻辑
        /// </summary>
        private async Task ExecuteRefundSuccessAsync(RefundOrder refund, PayOrder payOrder)
        {
            switch (refund.BusinessType)
            {
                case BusinessTypeEnum.VenueSite:
                    await SetVenueRefundOrderAsync(refund, payOrder);
                    break;
                case BusinessTypeEnum.Activity:
                    await SetActivityRefundOrderAsync(refund, payOrder);
                    break;
            }
        }
        #region 退款成功 相关业务逻辑
        /// <summary>
        /// 场馆订单退款单成功处理
        /// </summary>
        private async Task SetVenueRefundOrderAsync(RefundOrder refund, PayOrder payOrder)
        {
            //场馆会员卡支付退款，不计入场馆账户（场馆会员卡线下收费）
            if (refund.RefundType != PayTypeEnum.VenueMemberCard)
            {
                var siteOrder = await _siteOrderRepository.FirstOrDefaultAsync(m => m.ID == payOrder.BusinessId);
                var venueAccount = await _venueInfoAccountRepository.FirstOrDefaultAsync(m => m.VenueInfoID == siteOrder.VenueInfoID);
                if (venueAccount == null)
                {
                    _logger.LogError($"未查询到场馆账户:{siteOrder.VenueInfoID}");
                    return;
                }

                //全部退款，更新场馆订单状态
                if (payOrder.PayState == PayOrderStateEnum.Refunded)
                {
                    siteOrder.SO_State = VenueOrderStateEnum.Completed;
                    await _siteOrderRepository.UpdateAsync(siteOrder);
                }

                //核单状态为待评价及退款售后时，需要减去场馆账户金额
                if (siteOrder.SO_State == VenueOrderStateEnum.NoEvaluate || siteOrder.SO_State == VenueOrderStateEnum.Refund)
                {
                    var oldTotal = venueAccount.AccountTotal;
                    venueAccount.CanWithdrawTotal -= refund.RefundAmount;
                    venueAccount.AccountTotal -= refund.RefundAmount;
                    await _venueInfoAccountRepository.UpdateAsync(venueAccount);

                    var venueAccountDetail = new VenueInfoAccountDetail()
                    {
                        VIAD_Type = VenueAccountOperateEnum.Reduce,
                        VIAD_Source = VenueAccountSourceEnum.SiteOrderReturn,
                        VIAD_BeforeNum = oldTotal,
                        VIAD_Num = refund.RefundAmount,
                        VIAD_Explain = $"订单手动退款：{siteOrder.SO_OrderNo};退款总金额：{refund.RefundAmount}",
                        VenueInfoAccountID = venueAccount.ID,
                        VIAD_AfterNum = venueAccount.AccountTotal
                    };
                    await _venueInfoAccountDetailRepository.AddAsync(venueAccountDetail);
                }

                //假如产生服务费用
                if (refund.ServiceChargeAmount > 0)
                {
                    venueAccount = await _venueInfoAccountRepository.FirstOrDefaultAsync(m => m.VenueInfoID == siteOrder.VenueInfoID);
                    var oldTotal = venueAccount.AccountTotal;

                    venueAccount.AccountTotal += refund.ServiceChargeAmount;
                    venueAccount.CanWithdrawTotal += refund.ServiceChargeAmount;
                    await _venueInfoAccountRepository.UpdateAsync(venueAccount);

                    var venueAccountDetail = new VenueInfoAccountDetail()
                    {
                        VIAD_Type = VenueAccountOperateEnum.Add,
                        VIAD_Source = VenueAccountSourceEnum.SiteOrder,
                        VIAD_BeforeNum = oldTotal,
                        VIAD_Num = refund.ServiceChargeAmount,
                        VIAD_Explain = $"取消订单：：{siteOrder.SO_OrderNo};退款后结余总金额：{refund.ServiceChargeAmount}",
                        VenueInfoAccountID = venueAccount.ID,
                        VIAD_AfterNum = venueAccount.AccountTotal
                    };
                    await _venueInfoAccountDetailRepository.AddAsync(venueAccountDetail);
                }
            }
        }

        /// <summary>
        /// 活动订单退款单成功处理
        /// </summary>
        private async Task SetActivityRefundOrderAsync(RefundOrder refund, PayOrder payOrder)
        {
            var gameOrder = await _gameOrderRepository.FirstOrDefaultAsync(m => m.ID == payOrder.BusinessId);
            var refundUserIdList = GetRefundUserIdList(refund.ExtJson);
            await using (var redlock = await _distributedLockFactory.CreateLockAsync(gameOrder.BusinessId.ToString("N"), TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(1)))
            {
                if (!redlock.IsAcquired)
                {
                    throw new Exception($"退款通道拥堵:{gameOrder.ID}");
                }

                gameOrder.State = payOrder.PayState == PayOrderStateEnum.Refunded ? GameOrderStateEnum.Completed : GameOrderStateEnum.PartialRefunded;
                gameOrder.RefundAmount = payOrder.RefundAmount;
                var activity = await _activityRepository.FirstOrDefaultAsync(m => m.ID == gameOrder.BusinessId);
                if (activity != null)
                {
                    activity.TotalCount = activity.TotalCount - refundUserIdList.Count > 0 ? activity.TotalCount - refundUserIdList.Count : 0;
                }

                var activityUserBuilder = await _activityUserRepository.UpdatePartialAsync();
                activityUserBuilder = activityUserBuilder.Set(m => m.PayState, PayOrderStateEnum.Refunded)
                    .Set(m => m.JoinState, GameJoinStateEnum.Cancel).Where(m => m.GameOrderId == gameOrder.ID && refundUserIdList.Contains(m.UserId));

                await _activityRepository.UpdateAsync(activity);
                await _gameOrderRepository.UpdateAsync(gameOrder);
                await activityUserBuilder.ExecuteAsync();
            }
        }

        /// <summary>
        /// 获取额外数据中的活动报名人ID
        /// </summary>
        private List<Guid> GetRefundUserIdList(string extJson)
        {
            var result = new List<Guid>();
            try
            {
                result = JsonTool.JsonDeserialize<List<Guid>>(extJson);
                return result;
            }
            catch
            {
                return result;
            }
        }
        #endregion

        #endregion
    }
}
